package cn.ultrarisk.scadmin.manager.biz.stat.dao;

import cn.ultrarisk.mybatis.extension.domain.Entity;
import cn.ultrarisk.mybatis.extension.query.Query;
import cn.ultrarisk.scadmin.manager.biz.solr.context.SolrState;
import cn.ultrarisk.scadmin.manager.biz.solr.dao.SolrCollectionDAO;
import cn.ultrarisk.scadmin.manager.biz.solr.dao.SolrNodeDAO;
import cn.ultrarisk.scadmin.manager.biz.solr.dao.SolrReplicaDAO;
import cn.ultrarisk.scadmin.manager.biz.stat.context.StatType;
import cn.ultrarisk.scadmin.manager.biz.stat.dto.HighchartResult;
import cn.ultrarisk.scadmin.manager.biz.stat.dto.HighchartSerie;
import cn.ultrarisk.scadmin.manager.biz.stat.dto.StatisticsFilter;
import cn.ultrarisk.scadmin.manager.biz.stat.entity.SolrReplicaStat;
import cn.ultrarisk.scadmin.manager.exception.BizCheckedException;
import cn.ultrarisk.scadmin.manager.support.BaseDAO;
import cn.ultrarisk.mybatis.extension.query.Column;
import cn.ultrarisk.scadmin.manager.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;

/**
 * solr副本统计数据操作类
 *
 * @author sevendlong(lin23871@163.com)
 * @date 2014/3/28
 * @since V1.0
 */
@Repository
public class SolrReplicaStatDAO extends BaseDAO<SolrReplicaStat, Long> {
    @Autowired
    private SolrNodeDAO solrNodeDAO;
    @Autowired
    private SolrCollectionDAO solrCollectionDAO;
    @Autowired
    private SolrReplicaDAO solrReplicaDAO;

    /**
     * 构造器
     */
    public SolrReplicaStatDAO() {
        super(SolrReplicaStat.class, SolrReplicaStat.COLUMN_PROPERTY_MAP);
    }

    public List<SolrReplicaStat> buildStat(long startTime, long endTime) {
        Query query = Query.gteQuery(SolrReplicaStat.START_TIME, startTime).lt(SolrReplicaStat.START_TIME, endTime);
        return sqlSessionTemplate.selectList(this.entityName + ".buildStat", query.toMap(tableName));
    }

    public HighchartResult getAvgQpsStat(StatisticsFilter filter) {
        return getStat(filter, Column.Fx.AVG, SolrReplicaStat.AVG_QPS);
    }

    public HighchartResult getMaxQpsStat(StatisticsFilter filter) {
        return getStat(filter, Column.Fx.MAX, SolrReplicaStat.MAX_QPS);
    }

    public HighchartResult getVisitStat(StatisticsFilter filter) {
        List<String> groupKeys = new ArrayList<String>();
        if (StatisticsFilter.DIMENSION_REPLICA == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.REPLICA_ID);
        } else if (StatisticsFilter.DIMENSION_COLLECTION == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.COLLECTION_ID);
        } else if (StatisticsFilter.DIMENSION_NODE == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.NODE_ID);
        } else {
            throw new BizCheckedException("filter is error");
        }
        Long starTime = DateUtil.getDayBeginTime(filter.getStartTime());
        Long endTime = DateUtil.getDayEndTime(filter.getEndTime());

        Query query = new Query();
        query.eq(SolrReplicaStat.NODE_ID, filter.getNodeId());
        query.eq(SolrReplicaStat.COLLECTION_ID, filter.getCollectionId());
        query.eq(SolrReplicaStat.REPLICA_ID, filter.getReplicaId());
        query.gte(SolrReplicaStat.START_TIME, starTime);
        query.lt(SolrReplicaStat.START_TIME, endTime);
        query.setGroups(groupKeys);

        String[] tableColumns = new String[]{
                Column.as(groupKeys.get(0), "refId"),
                Column.fx(Column.Fx.SUM, SolrReplicaStat.VISIT_COUNT)
        };
        List<Entity> stats = findEntityList(query, tableColumns);
        List<Integer> refIds = new ArrayList<Integer>();
        for (Map<String, Object> stat : stats) {
            refIds.add(Integer.parseInt(stat.get("refId").toString()));
        }
        Map<Integer, String> nameMap = null;
        if (StatisticsFilter.DIMENSION_REPLICA == filter.getDimension()) {
            nameMap = solrReplicaDAO.getNameMap(refIds, true);
        } else if (StatisticsFilter.DIMENSION_COLLECTION == filter.getDimension()) {
            nameMap = solrCollectionDAO.getNameMap(refIds);
        } else if (StatisticsFilter.DIMENSION_NODE == filter.getDimension()) {
            nameMap = solrNodeDAO.getNameMap(refIds);
        }

        if (nameMap != null) {
            Map<String, HighchartSerie> series = new HashMap<String, HighchartSerie>();
            for (Map<String, Object> stat : stats) {
                String name = nameMap.get(Integer.parseInt(stat.get("refId").toString()));
                if (name != null && name.length() > 0) {
                    HighchartSerie serie = new HighchartSerie();
                    serie.setName(name);
                    serie.addData(name, stat.get(SolrReplicaStat.VISIT_COUNT));
                    series.put(name, serie);
                }
            }
            List<HighchartSerie> serieList = new ArrayList<HighchartSerie>(series.values());
            Collections.sort(serieList, new Comparator<HighchartSerie>() {
                @Override
                public int compare(HighchartSerie o1, HighchartSerie o2) {
                    Long v1 = Long.parseLong(o1.getData().get(o1.getName()).toString());
                    Long v2 = Long.parseLong(o2.getData().get(o2.getName()).toString());
                    return v1 < v2 ? 1 : -1;
                }
            });
            return new HighchartResult(serieList);
        }
        return null;
    }

    public HighchartResult getGrowStat(StatisticsFilter filter) {
        return getStat(filter, Column.Fx.AVG, SolrReplicaStat.DOCS);
    }

    public HighchartResult getCacheStat(StatisticsFilter filter) {
        return getStat(filter, Column.Fx.AVG, SolrReplicaStat.HITS);
    }

    private HighchartResult getStat(StatisticsFilter filter, Column.Fx fx, String column) {
        List<String> groupKeys = new ArrayList<String>();
        if (StatisticsFilter.DIMENSION_REPLICA == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.REPLICA_ID);
        } else if (StatisticsFilter.DIMENSION_COLLECTION == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.COLLECTION_ID);
        } else if (StatisticsFilter.DIMENSION_NODE == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.NODE_ID);
        } else {
            throw new BizCheckedException("filter is error");
        }
        Long starTime = DateUtil.getDayBeginTime(filter.getStartTime());
        Long endTime = DateUtil.getDayEndTime(filter.getEndTime());
        List<Object> categories = new ArrayList<Object>();
        if (filter.getStatType() == StatType.HOUR) {
            groupKeys.add("FROM_UNIXTIME(start_time / 1000, '%Y%m%d%H')");
            for (Long time = starTime; time <= endTime; time = DateUtil.addHour(time, 1)) {
                categories.add(time);
            }
        } else if (filter.getStatType() == StatType.DAY) {
            groupKeys.add("FROM_UNIXTIME(start_time / 1000, '%Y%m%d')");
            for (Long time = starTime; time <= endTime; time = DateUtil.addDay(time, 1)) {
                categories.add(time);
            }
        } else if (filter.getStatType() == StatType.WEEK) {
            groupKeys.add("FROM_UNIXTIME(start_time / 1000, '%Y%u')");
            for (Long time = starTime; time <= endTime; time = DateUtil.addMonth(time, 1)) {
                categories.add(time);
            }
        } else if (filter.getStatType() == StatType.MONTH) {
            groupKeys.add("FROM_UNIXTIME(start_time / 1000, '%Y%m')");
            for (Long time = starTime; time <= endTime; time = DateUtil.addMonth(time, 1)) {
                categories.add(time);
            }
        } else {
            throw new BizCheckedException("filter is error");
        }
        Query query = new Query();
        query.eq(SolrReplicaStat.NODE_ID, filter.getNodeId());
        query.eq(SolrReplicaStat.COLLECTION_ID, filter.getCollectionId());
        query.eq(SolrReplicaStat.REPLICA_ID, filter.getReplicaId());
        query.gte(SolrReplicaStat.START_TIME, starTime);
        query.lt(SolrReplicaStat.START_TIME, endTime);
        query.setGroups(groupKeys);

        String[] tableColumns = new String[]{
                Column.as(groupKeys.get(0), "refId"),
                Column.min(SolrReplicaStat.START_TIME),
                Column.fx(fx, column)
        };
        List<Entity> stats = findEntityList(query, tableColumns);
        List<Integer> refIds = new ArrayList<Integer>();
        for (Map<String, Object> stat : stats) {
            refIds.add(Integer.parseInt(stat.get("refId").toString()));
        }
        Map<Integer, String> nameMap = null;
        if (StatisticsFilter.DIMENSION_REPLICA == filter.getDimension()) {
            nameMap = solrReplicaDAO.getNameMap(refIds, true);
        } else if (StatisticsFilter.DIMENSION_COLLECTION == filter.getDimension()) {
            nameMap = solrCollectionDAO.getNameMap(refIds);
        } else if (StatisticsFilter.DIMENSION_NODE == filter.getDimension()) {
            nameMap = solrNodeDAO.getNameMap(refIds);
        }

        if (nameMap != null) {
            Map<String, HighchartSerie> series = new HashMap<String, HighchartSerie>();
            for (Map<String, Object> stat : stats) {
                Long startTime = Long.parseLong(stat.get(SolrReplicaStat.START_TIME).toString());
                String name = nameMap.get(Integer.parseInt(stat.get("refId").toString()));
                HighchartSerie serie = series.get(name);
                if (serie == null) {
                    serie = new HighchartSerie();
                }
                for (Object category : categories) {
                    if (category.equals(startTime)) {
                        serie.addData(startTime, stat.get(column));
                    }
                }
                series.put(name, serie);
            }
            for (String name : series.keySet()) {
                HighchartSerie serie = series.get(name);
                serie.setName(name);
                for (Object category : categories) {
                    if (!serie.getData().containsKey(category)) {
                        serie.addData(category, 0);
                    }
                }
            }
            return new HighchartResult(categories, new ArrayList<HighchartSerie>(series.values()));
        }
        return null;
    }

    public HighchartResult getStatusStat(StatisticsFilter filter) {
        List<String> groupKeys = new ArrayList<String>();
        if (StatisticsFilter.DIMENSION_REPLICA == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.REPLICA_ID);
        } else if (StatisticsFilter.DIMENSION_COLLECTION == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.COLLECTION_ID);
        } else if (StatisticsFilter.DIMENSION_NODE == filter.getDimension()) {
            groupKeys.add(SolrReplicaStat.NODE_ID);
        } else {
            throw new BizCheckedException("filter is error");
        }
        Long starTime = DateUtil.getDayBeginTime(filter.getStartTime());
        Long endTime = DateUtil.getDayEndTime(filter.getEndTime());
        List<Object> categories = new ArrayList<Object>();

        Query query = new Query();
        query.eq(SolrReplicaStat.NODE_ID, filter.getNodeId());
        query.eq(SolrReplicaStat.COLLECTION_ID, filter.getCollectionId());
        query.eq(SolrReplicaStat.REPLICA_ID, filter.getReplicaId());
        query.gte(SolrReplicaStat.START_TIME, starTime);
        query.lt(SolrReplicaStat.START_TIME, endTime);
        query.setGroups(groupKeys);

        String[] tableColumns = new String[]{
                Column.as(groupKeys.get(0), "refId"),
                Column.sum(SolrReplicaStat.LEADER_STATE),
                Column.sum(SolrReplicaStat.ACTIVE_STATE),
                Column.sum(SolrReplicaStat.RECOVERING_STATE),
                Column.sum(SolrReplicaStat.DOWN_STATE),
                Column.sum(SolrReplicaStat.RECOVER_FAILED_STATE),
                Column.sum(SolrReplicaStat.GONE_STATE)
        };
        List<Entity> stats = findEntityList(query, tableColumns);
        List<Integer> refIds = new ArrayList<Integer>();
        for (Map<String, Object> stat : stats) {
            refIds.add(Integer.parseInt(stat.get("refId").toString()));
        }
        Map<Integer, String> nameMap = null;
        if (StatisticsFilter.DIMENSION_REPLICA == filter.getDimension()) {
            nameMap = solrReplicaDAO.getNameMap(refIds, true);
        } else if (StatisticsFilter.DIMENSION_COLLECTION == filter.getDimension()) {
            nameMap = solrCollectionDAO.getNameMap(refIds);
        } else if (StatisticsFilter.DIMENSION_NODE == filter.getDimension()) {
            nameMap = solrNodeDAO.getNameMap(refIds);
        }

        if (nameMap != null) {
            categories.addAll(nameMap.values());
            Map<String, HighchartSerie> series = new LinkedHashMap<String, HighchartSerie>();
            series.put(SolrReplicaStat.LEADER_STATE, new HighchartSerie(SolrState.LEADER.toString()));
            series.put(SolrReplicaStat.ACTIVE_STATE, new HighchartSerie(SolrState.ACTIVE.toString()));
            series.put(SolrReplicaStat.RECOVERING_STATE, new HighchartSerie(SolrState.RECOVERING.toString()));
            series.put(SolrReplicaStat.DOWN_STATE, new HighchartSerie(SolrState.DOWN.toString()));
            series.put(SolrReplicaStat.RECOVER_FAILED_STATE, new HighchartSerie(SolrState.RECOVERY_FAILED.toString()));
            series.put(SolrReplicaStat.GONE_STATE, new HighchartSerie(SolrState.GONE.toString()));
            for (Map<String, Object> stat : stats) {
                String name = nameMap.get(Integer.parseInt(stat.get("refId").toString()));
                series.get(SolrReplicaStat.LEADER_STATE).addData(name, stat.get(SolrReplicaStat.LEADER_STATE));
                series.get(SolrReplicaStat.ACTIVE_STATE).addData(name, stat.get(SolrReplicaStat.ACTIVE_STATE));
                series.get(SolrReplicaStat.RECOVERING_STATE).addData(name, stat.get(SolrReplicaStat.RECOVERING_STATE));
                series.get(SolrReplicaStat.DOWN_STATE).addData(name, stat.get(SolrReplicaStat.DOWN_STATE));
                series.get(SolrReplicaStat.RECOVER_FAILED_STATE).addData(name, stat.get(SolrReplicaStat.RECOVER_FAILED_STATE));
                series.get(SolrReplicaStat.GONE_STATE).addData(name, stat.get(SolrReplicaStat.GONE_STATE));
            }
            return new HighchartResult(categories, new ArrayList<HighchartSerie>(series.values()));
        }
        return null;
    }
}
